
#ifndef _DEFERRED_SHADERS_H
#define _DEFERRED_SHADERS_H

#define INVERSE_4PI 0.07957747154594766788444188168626f

#define REG_POS 0
#define REG_NORMAL 1
#define REG_TEXCOORDS 2

//#define ZBUFFER

// Next section is solely for shaders (C/C++ compilers must define __TIMESTAMP__)
// This way it's possible to include this file in both, shaders and c++ code
#ifndef __TIMESTAMP__
uniform Matrices {
    mat4 Projection;
    mat4 Camera;
    mat3 NormalC;
} GlobalMatrices;

uniform Model {
    mat4 ModelView;
    mat3 NormalM;
} LocalModel;

uniform MaterialAttrs {
    vec4 diffuse;
    vec4 extra;
} Material;

uniform Light {
    vec3 pos;
    vec4 color;
} cLight;

const vec3 cEye=vec3(0,0,0);

vec3 Lighting(const in vec3 normal, const in vec3 location, const in vec4 material, const in float roughness)
{
    vec3 outColor=vec3(0,0,0);
    vec3 view=normalize(cEye-location);

    vec3 incoming=location-cLight.pos;
    float aten=inversesqrt(dot(incoming,incoming));
    incoming*=aten;
    aten*=aten*INVERSE_4PI*cLight.color.a;
    // outColor-=min(0, dot(incoming, normal))*cLight.color.rgb*aten*material.rgb;
    outColor-=dot(incoming, normal)*cLight.color.rgb*aten*material.rgb;
    // Obtain <N,H>
    vec3 reflected=reflect(incoming, normal);
    float spec=(dot(reflected, view)+1.0f)*0.5;
    float smoothness=1/(roughness*roughness);
    spec=1/spec;
    // compute the coefficient
    spec=exp((1-spec)*smoothness)*smoothness*spec*spec*INVERSE_4PI*4.0f;
    // nullify in case when not facing the light
    // currently no need since back facing faces will be discarded
    // spec*=(sign(dot(reflected,normal))+1.0f)*0.5;
    outColor+=spec*cLight*aten*material.a;

    return outColor;
}

vec4 ProjectVertex(const in mat4 Projection, const in vec4 Position)
{
    vec4 pPos=Projection*Position;
#ifndef ZBUFFER
    // wbuffer
    pPos.z*=pPos.w;
#endif
    return pPos;
}

vec4 UnProjectVertex(const in mat4 InvProjection, const in vec3 ndcPos, const in vec2 NearFar)
{
    vec4 pos;
    pos.xyz=ndcPos;
#ifndef ZBUFFER
    pos.w=-0.5f*dot(NearFar, vec2(1-ndcPos.z, 1+ndcPos.z));
    pos.xy*=pos.w;
#else
    pos.w=-2.0f*NearFar.x*NearFar.y/dot(NearFar, vec2(1+ndcPos.z, 1-ndcPos.z));
    pos.xyz*=pos.w;
#endif
    return InvProjection*pos;
}

// __TIMESTAMP__
#endif

// _DEFERRED_SHADERS_H
#endif
